/*
 * pldtc_config.c
 *
 *  Created on: 2016Äê3ÔÂ14ÈÕ
 *      Author: huangkaibin
 */

#ifndef __PLDTC_H__
#define __PLDTC_H__

#include "typedef.h"
#include "plfault_monitor.h"
#include "pldid.h"

//#define DTC_STATUS_AVAILABLE_MASK (0xFFU)
#define DTC_STATUS_AVAILABLE_MASK (0x09U)//(0x7FU)

#define ZERO_DTC_CONFIG()  {INVALID_DTC_CODE, 0U, 0U, NULL, 0U}
#define INVALID_DTC_CONFIG_INDEX (0xFFU)
#define INVALID_SNAP_BUFFER_INDEX (0xFFU)
#define INVALID_RECORD_INDEX (0xFFU) /*very import: this must be 0xFF, and can not be changed to others*/
#define RECORD_NUMBER_FOR_ALL (0xFFU)

#define define_exact_time_record(occurring_time, record_number) ((uint16)(((EXACT_TIME_RECORD | ((occurring_time) & 0x0FU)) << 8U) | (uint8)(record_number)))
#define define_latest_time_record(record_number) ((uint16)(((LATEST_TIME_RECORD) << 8U) | (uint8)(record_number)))
#define define_first_time_record(record_number) define_exact_time_record(1, record_number)


typedef enum {
	DTC_EEP_CLEAR_FINISHED = 0x00U,
	DTC_EEP_CLEAR_REQUESTED,
	DTC_EEP_STATUS_CLEARED,
	DTC_EEP_SNAP_CLEARED,
} PlDTCEepClearState;

typedef struct {
	uint8 testFailed: 1; /*this is bit0 for HCS12 compiler*/
	uint8 testFailedThisOperationCycle: 1;
	uint8 pendingDTC: 1;
	uint8 confirmedDTC: 1;
	uint8 testNotCompletedSinceLastClear: 1;
	uint8 testFailedSinceLastClear: 1;
	uint8 testNotCompletedThisOperationCycle: 1;
	uint8 warningIndicatorRequested: 1;
} PlDtcStatusBit; /*statusOfDTC, note: relative with endian*/

typedef union {
	uint8 dtc_status;
	PlDtcStatusBit status_bits; /*statusOfDTC, note: relative with endian*/
} PlDtcStatus; /*statusOfDTC, note: relative with endian*/

typedef struct {
	uint16 range_data_mark; /*0x55AA to indicate that there has learned data on EEPROM*/
	PlDtcStatus dtc_status; /*one byte, store EEPROM, clear by diag*/
	uint8 dtc_aging_count; /*op cycles with no fault occurred, store EEPROM clear by diag*/
	uint8 dtc_aged_count; /*dtc cleared count due to aged, store EEPROM clear by diag*/
	uint8 fault_occur_op_cycles; /*store EEPROM, clear by diag*/
	uint8 fault_pending_count; /*store EEPROM, clear by diag*/
	uint32 last_fault_odometer;/*store EEPROM, last fault occur odometer, clear by diag*/
	uint8 range_data_crc;
} PlDtcEepMirror;


typedef struct {
	uint8  enabled;
	uint8  monitor_index;
	bool   eep_load_result;

	uint8  snap_record_count;
	uint16 total_snap_data_size;
	uint16 snap_record_offset;

	/*The offset of eep address from the start address of snapshot area.
	 * For each snapshot record, did number will also be saved to eeprom.
	 * */
	uint16 snap_eep_address_offset;

	uint8 eep_clear_state;
	uint8 reserved;
} PlDtcInfo;

typedef struct {
	uint32 dtc_code; /*unused byte, high byte, middle byte, low byte*/
	uint8  pending_count_for_confirm;
	uint8  dtc_aging_thresold;
	const PlDidRecordList record_list;
	uint8  priority;
} PlDtcConfig;

#define MAX_SNAP_BUFFER_SIZE (70U)
#define SNAP_BUFFER_COUNT (5U)

typedef struct {
	uint8 assigned_dtc_config_index;
	bool buffer_acquired;
	uint16 record_updated_bits;
	uint16 record_saved_bits;
	uint8 data[MAX_SNAP_BUFFER_SIZE];
} PlDtcSnapBuffer;

typedef struct {
	uint8 record_data_size;
	uint8 record_data_offset;
	uint8 record_did_count;
} PlDtcSnapRecordStatus;

typedef enum {
	EXACT_TIME_RECORD = 0x10U, /*The record for fault occurred at the specified time*/
	LATEST_TIME_RECORD = 0x20U, /*The record for latest occurred fault*/
} PlDtcRecordType;



extern PlDtcConfig pldtc_dtc_config[];
extern PlDtcEepMirror pldtc_eep_mirror[];
extern PlDtcInfo pldtc_info[];
extern const uint8 pldtc_config_count;
extern uint8 pldtc_eep_mirror_config_index;
extern uint8 pldtc_eep_snapshot_config_index;

extern PlDtcSnapBuffer pldtc_snap_buffer_pool[];

extern void pldtc_monitor_init(void);
extern void pldtc_monitor_task(void);
extern bool pldtc_save_snapshot(void);
extern void pldtc_save_snapshot_task(void);
extern void pldtc_enter_sleep(void);

extern uint8 pldtc_find_dtc_config_index(uint32 dtc_code);


extern uint16 pldtc_get_dtc_count_and_fill_dtc_code_by_status_mask(uint8 status_mask, uint8* dest_buffer, bool all_dtc);

extern uint8 pldtc_get_dtc_status_for_config(uint8 dtc_config_index);
extern void pldtc_supress_dtc_updating(bool should_supress_updating);
extern uint8 pldtc_fill_dtc_code_to_buffer_from_config(uint8 dtc_config_index, uint8 *buffer, bool should_fill_status);

extern bool pldtc_clear_diag(void);
extern void pldtc_request_clear_diag(uint8 dtc_config_index, bool clear_due_aged);
extern void pldtc_request_clear_all_diag(void);
extern bool pldtc_should_take_snapshot(uint8 record_type, uint8 fault_occurring_time);
extern bool pldtc_take_snapshot(uint8 dtc_config_index, uint8 record_number, bool *snap_buffer_failed, bool force_use_default, uint8 fault_occurring_time);
extern bool pldtc_store_snapshot_to_eeprom(uint8 dtc_config_index, uint8 record_index, uint8* ram_buffer);

extern bool pldtc_load_snapshot_from_eeprom_by_record_index(uint8 dtc_config_index, uint8 record_index, uint8* ram_buffer, uint16* filled_length, uint8 *did_count_ptr, bool should_fill_record_number);
extern bool pldtc_load_snapshot_from_eeprom_by_record_number(uint8 dtc_config_index, uint8 record_number, uint8* ram_buffer, uint16* filled_length, bool should_fill_record_number);
extern bool pldtc_load_snapshot_identification_by_record_number(uint8* ram_buffer, uint16* filled_length);

extern uint8 pldtc_get_dtc_status(uint32 dtc_code);
extern void pldtc_wait_until_dtc_eep_completed(void);
extern void  plcan_fill_signal_dtc_status_message(uint8 dtc_config_index,PlcanDataBuffer *buffer);


#define pldtc_get_dtc_code_from_buffer(buffer, offset) ((((uint32)((const uint8*)(buffer))[(offset) + 0U]) << 16U) | (((uint32)((const uint8*)(buffer))[(offset) + 1U]) << 8U) | (((uint32)((const uint8*)(buffer))[(offset) + 2U]) << 0U))
#define pldtc_get_dtc_raw_status_for_config(dtc_config_index) (pldtc_eep_mirror[dtc_config_index].dtc_status)
//#define pldtc_get_dtc_status_for_config(dtc_config_index) (pldtc_eep_mirror[dtc_config_index].dtc_status.dtc_status)
//#define pldtc_get_record_number_from_dtc_config(dtc_config, record_index) ((uint8)((dtc_config)->record_list.did_record_list[record_index].record_and_did_numbers[0]))
#define pldtc_get_record_number_from_dtc_config(dtc_config, record_index) ((uint8)pldid_get_did_record_number(pldid_get_did_record((dtc_config)->record_list, record_index)))
#define pldtc_get_record_type_from_dtc_config(dtc_config, record_index)   ((uint8)pldid_get_did_record_type(pldid_get_did_record((dtc_config)->record_list, record_index)))

#define pldtc_get_available_dtc_status_mask() (DTC_STATUS_AVAILABLE_MASK)

#define pldtc_fill_dtc_code_to_buffer(buffer, offset, dtc_code) do { \
	((uint8*)(buffer))[(offset) + 0U] = ((dtc_code >> 16U) & 0xFFU); \
	((uint8*)(buffer))[(offset) + 1U] = ((dtc_code >> 8U) & 0xFFU); \
	((uint8*)(buffer))[(offset) + 2U] = ((dtc_code >> 0U) & 0xFFU); \
} while(0)

#define pldtc_fill_all_supported_dtc_code(dest_buffer) pldtc_get_dtc_count_and_fill_dtc_code_by_status_mask(0x00U, dest_buffer,TRUE) /*status mask set zero to include all dtc codes*/
#define pldtc_get_dtc_count_by_status_mask(status_mask) pldtc_get_dtc_count_and_fill_dtc_code_by_status_mask(status_mask, NULL,FALSE)
#define pldtc_take_full_snapshot(dtc_config_index, snap_buffer_failed, force_use_default, fault_occurring_time) pldtc_take_snapshot(dtc_config_index, RECORD_NUMBER_FOR_ALL, snap_buffer_failed, force_use_default, fault_occurring_time)


#endif /* __PLDTC_H__ */
